使用 Kubernetes 部署访问你的第一个应用
Changelog
2021.11.10
-
Ingress apiVersion的变化。从Kubernetes v1.8+ 开始,apiVersion变更为networking.k8s.io/v1beta1。废弃extensions/v1beta1。
-
结构体的变化。移除了spec.backend字段;backend下的service也会接着细化。主要修改为:
- 移除了spec.backend字段
- backend.serviceName,backend.servicePort 更换为了backend.service.name,backend.service.port.number
-
新增了必填字段:pathType。其功能作用是精确匹配和前缀匹配的区别。
例如 path:/wss,pathType: Prefix,等同于path: /wss*。具体详细内容:https://kubernetes.io/zh/docs/concepts/services-networking/ingress/#path-types
- 更新 ingress 版本到最新 stable 1.0.4 版本,原有的镜像源会失效。我也没找到好的镜像,希望大家如果有挖掘可以提供
前言
在上一章,我们部署了一套 Kubernetes 集群环境,这一章我们就来部署自己的第一个 Kubernetes 应用并实现访问。
声明一份配置清单
在开始部署前,我们先要声明一份 配置清单 ,清单的文件格式为 YAML 文件格式。在 Kubernetes 中,应用部署完全可以通过 YAML 配置清单来进行部署。
新建一个文件夹,名称叫 deployment,并在文件夹内创建一份 yaml 文件,名称为 v1:
mkdir deployment && cd deployment
vim v1.yaml接着在配置文件中,写入以下内容:
apiVersion: apps/v1
kind: Deployment
metadata:
name: front-v1
spec:
selector:
matchLabels:
app: nginx-v1
replicas: 3
template:
metadata:
labels:
app: nginx-v1
spec:
containers:
- name: nginx
image: registry.cn-hangzhou.aliyuncs.com/janlay/k8s_test:v1
ports:
- containerPort: 80我们关注下 YAML 文件中的 kind 字段。这是在声明 Kubernetes 的资源类型。在这里,我们的 kind 值为 deployment。那 deployment 又是什么呢?
什么是 Deployment
如果你将 k8s 看作是一个大型机场,那么 deployment 刚好就是机场内的停机坪。
根据飞机的种类进行划分停机坪,不同的停机坪都停着不同类型的飞机。只不过,deployment 要比停机坪还要灵活,随时可以根据剩余的空地大小(服务器剩余资源)和塔台的指令,增大/变小停机坪的空间。这个“增大变小停机坪空间的动作”,在k8s中就是 deployment 对它下面所属容器数量的扩容/缩小的操作。
那么这也就代表,deployment是无状态的,也就不会去负责停机坪中每架飞机之间的通信和组织关系。只需要根据塔台的指令,维护好飞机的更新和进出指令即可。这个根据指令维护飞机更新和进出的行为,在k8s中就是 deployment 对他下面的容器版本更新升级,暂停和恢复更新升级的动作。
在这里的容器,并不等于 Docker 中的容器。它在K8S中被称为 Pod 。那么 Pod 是什么 ?
什么是 Pod
Pod 是 K8S 中最小的可调度单元(可操作/可部署单元),它里面可以包含1个或者多个 Docker 容器。在 Pod 内的所有 Docker 容器,都会共享同一个网络、存储卷、端口映射规则。一个 Pod 拥有一个 IP。
但这个 IP 会随着Pod的重启,创建,删除等跟着改变,所以不固定且不完全可靠。这也就是 Pod 的 IP 漂移问题。这个问题我们可以使用下面的 Service 去自动映射 我们经常会把 Pod 和 Docker 搞混,这两者的关系就像是豌豆和豌豆荚,Pod 是一个容器组,里面有很多容器,容器组内共享资源。
分析配置文件构成
至此对 deployment 应该有了大体的概念。当然,kind 字段不只可以声明 deploymnt ,还可以声明其他的资源类型。重要的我们在后面的章节中都会写到。
了解了 deployment 是啥后,我们来看看配置清单中的字段都代表的是啥。我们将配置分成三段去进行阅读:
最上面的第一段声明了当前资源配置的 API 版本,资源类型和资源名称:
- API 配置版本:
apps/v1 - 资源类型:
deployment - 资源名称:
deplyment的名称叫front-v1
其中,API 配置版本会随着 K8S 版本迭代和资源类型不同有变化。具体可以看下面这个链接:
该怎么选择 apiVersion 的值: https://matthewpalmer.net/kubernetes-app-developer/articles/kubernetes-apiversion-definition-guide.html
左边这一段,告诉 deployment 我根据规则匹配相应的 Pod 进行控制和管理。这里使用 matchLabels 字段匹配 Pod 的 label 值。
右边配置则代表声明一个 Pod 组:
- replicas:要创建的
Pod最大数量。数字类型 - labels.app:Pod 组的名称
- spec:组内创建的 Pod 信息
- name:Pod 名称
- image:以什么镜像创建 Pod。这里是 Docker 镜像地址
- ports.containerPort:Pod 内容器映射的端口
这里的镜像,我使用了自己编译的一份 nginx 镜像作为演示,也可以换成你自己的镜像
启动第一个应用
在k8s中,我们使用 kubectl apply 来执行一份k8s的配置:
kubectl apply -f ./v1.yaml其中,kubectl apply 代表准备对资源进行配置。 -f 等于 --filename,后面可以跟随多个配置文件。例如:
kubectl apply -f ./v1.yaml ./v1-service.yaml ./v1-ingress.yaml当提示下面文字时,代表配置文件执行成功:
如果你想看部署完毕后的 Pod 运行状态,可以使用 kubectl get pod 命令来获取所有 Pod 的信息:
kubectl get pod你会得到一个表格,这是 你自己在 K8S 中部署的所有的Pod。
其中,name 是Pod的名称;READY 为容器状态,格式为可用容器/所有容器数量;STATUS 为 Pod 的运行状态;RESTARTS 为重启数量;AGE 为 Pod 运行时间;当状态都是 Running 时,代表 Pod 运行正常。
令人费解的无状态
部署成功了,但怎么去访问具体应用呢?
前面我们写到, deployment 是无状态的。也就意味着, deployment 并不会对 pod 进行网络通信和分发。想访问服务,有以下两个办法:
- 直接访问具体的
Pod:这是一个办法,但是Pod太多了,达不到我们自动调度的效果。且Pod的IP在运行时还会经常进行漂移且不固定(后面会讲到)。 - 使用
Service组织统一的Pod访问入口。
这里我们选择另一种资源类型 —— Service 来进行统一组织 Pod 服务访问
访问第一个应用
这里我们使用 k8s 的 Service 来组织我们的访问入口。那什么是 Service?
什么是 Service
deployment 是停机坪,那么 Service 则是一块停机坪的统一通信入口。它负责自动调度和组织deployment中 Pod 的服务访问。由于自动映射 Pod 的IP,同时也解决了 Pod 的IP漂移问题。
下面这张图就印证了 Service 的作用。流量会首先进入 VM(主机),随后进入 Service 中,接着 Service 再去将流量调度给匹配的 Pod 。
Service 的配置
同样的,创建一个 Service 也需要一份 YAML 配置清单。一份简单的 Service 的配置如下:
apiVersion: v1
kind: Service
metadata:
name: front-service-v1
spec:
selector:
app: nginx-v1
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort其中比较熟悉的通用字段就不介绍了。有几个特有的字段需要关注下:
| 字段 | 解释 |
|---|---|
| protocol | 通信类型(TCP/UDP) |
| targetPort | 原本 Pod 开放的端口 |
| port | k8s 容器之间互相访问的端口 |
| type | NodePort,Service的一种访问方式 |
在这里,Service的模式我们选择使用 NodePort 模式。其他模式可以参考:http://www.dockerone.com/article/4884
与 Deployment 配置文件合并
根据YAML语法,我们可以将Service和deployment合并为同一个配置文件。当然,新建一个文件也是可以的。
我们编辑原有的v1.yaml,在文件底部添加 --- 继续拼接Service的配置:
vim ./v1.yaml编辑保存退出后,使用 kubectl apply 命令来更新配置:
kubectl apply -f ./v1.yaml此时,Service 已经部署完毕。
查看 Service 的访问端口
在部署成功 Service 后,我们可以使用 kubectl get svc 来获取我们已经部署的 Service 列表
我们可以使用 kubectl get svc 去查看下具体打开的服务端口:
kubectl get svc执行后,会展示相关结果。
其中, PORT 字段代表 Service 的访问端口。: 前为映射到Pod的端口,31048 为访问端口。
我们访问 Master节点IP + 端口,就可以访问到该服务。
ingress 是什么
在前面,我们部署了 deployment 和 Service,实现了对服务的访问。但是在实际使用中,我们还会根据请求路径前缀的匹配,权重,甚至根据 cookie/header 的值去访问不同的服务。为了达到这种负载均衡的效果,我们可以使用 k8s 的另一个组件 —— ingress
在日常开发中,我们经常会遇到路径分流问题。例如当我们访问 /a 时,需要返回A服务的页面。访问 /b,需要返回服务B的页面。这时候,我们就可以使用 k8s 中的 ingress 去实现。
在这里,我们选择 ingress-nginx。 ingress-nginx 是基于 nginx 的一个 ingress 实现。当然也可以实现正则匹配路径,流量转发,基于 cookie header 切分流量(灰度发布)。
部署 ingress
首先进入 master 节点,下载 ingress 配置文件:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.4/deploy/static/provider/baremetal/deploy.yaml接着编辑下部署文件,将 ingress 的 nodePort 端口改为 31234 ,以方便后面访问:
vim ./deploy.yaml在对应位置添加 nodePort 字段为 31234 ,https为 31235 。
接着执行命令使 ingress 生效:
kubectl apply -f deploy.yaml接下来会自动拉取 ingress 镜像,自动部署 ingress 。可以使用 kubectl 命令查看部署状态:
kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --watch如果显示以下信息,则代表部署成功。
输入以下命令,检查配置是否生效:
kubectl -n ingress-nginx get svc如果看到以下信息,代表生效:
配置 ingress
初识配置文件
同样的, ingress 服务的配置也是使用 yaml 文件进行管理。
我们新建一个 ingress 文件夹,将 ingress 的配置放在里面:
mkdir ingress && cd ingress && vim base.yaml拷贝以下内容进去:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
spec:
rules:
- http:
paths:
- path: /wss
pathType: Prefix
backend:
service:
name: front-service-v1
port:
number: 80这是一份简单的 ingress 配置文件。配置主要分三部分:
annotations
annotations 是 ingress 的主要配置项目,可以用来修改这些配置来修改 ingress 的行为。我们可以通过修改这些配置来实现灰度发布,跨域资源,甚至将 www.abc.com 重定向到 abc.com 。
具体详细配置解释,可以翻阅官网文档:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /rules
rules 是 ingress 配置路径转发规则的地方。 path 可以是一个路径字符串,也可以是一个正则表达式。
backend 则是 k8s 的 service 服务, serviceName 是服务名称, servicePort 是服务端口。
当我们去访问 /wss 时, ingress 就会帮我们调度到 front-service-v1 这个 service 上面。
rules:
- http:
paths:
- path: /wss
pathType: Prefix
backend:
service:
name: front-service-v1
port:
number: 80然后执行命令,使配置项目生效:
kubectl apply -f ./base.yaml访问 http://IP:31234,如果能看到服务页面则代表代表成功:
结尾
到这里,我们就成功地部署了自己的第一个Kubernetes应用,并实现了访问。
但是在实际开发中,我们还需要零宕机发布,设置灰度环境等需求。下一章我们就会讲解下,如何使用 Kubernetes 配置你自己的灰度和滚动发布环境